package com.haoran.dwz.common.redis;

import java.math.BigDecimal;
import java.text.MessageFormat;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.haoran.dwz.common.exception.UsmException;
import com.haoran.dwz.common.exception.ValidException;
import com.haoran.dwz.common.util.DisorderedCompressEncoder;
import com.haoran.dwz.service.SystemSetupService;
import com.haoran.dwz.util.MailUtil;


/**
 * <pre>
 * 1位 [0,63] 
 * 2位 [64,4095] 
 * 3位 [4096,262143] 
 * 4位 [262144,16777215] 
 * 5位 [16777216,1073741823]
 * </pre>
 */
public class RedisSequenceWorker {

	Logger logger = LoggerFactory.getLogger(getClass());

	public static final String SEQUENCE_ONE_LENGTH = "SEQUENCE:ONE_LENGTH";
	public static final String SEQUENCE_TWO_LENGTH = "SEQUENCE:TWO_LENGTH";
	public static final String SEQUENCE_THREE_LENGTH = "SEQUENCE:THREE_LENGTH";
	public static final String SEQUENCE_FOUR_LENGTH = "SEQUENCE:FOUR_LENGTH";
	public static final String SEQUENCE_FIVE_LENGTH = "SEQUENCE:FIVE_LENGTH";

	public static final long MIN_VALUE_ONE_LENGTH = 0;
	public static final long MIN_VALUE_TWO_LENGTH = 64;
	public static final long MIN_VALUE_THREE_LENGTH = 4096;
	public static final long MIN_VALUE_FOUR_LENGTH = 262144;
	public static final long MIN_VALUE_FIVE_LENGTH = 16777216;

	public static final long MAX_VALUE_ONE_LENGTH = 63;
	public static final long MAX_VALUE_TWO_LENGTH = 4095;
	public static final long MAX_VALUE_THREE_LENGTH = 262143;
	public static final long MAX_VALUE_FOUR_LENGTH = 16777215;
	public static final long MAX_VALUE_FIVE_LENGTH = 1073741823;

	private RedisSequenceFactory redisSequenceFactory;

	private SystemSetupService systemSetupService;
	
	private  MailUtil mailUtil;

	RedisSequenceWorker(RedisSequenceFactory redisSequenceFactory, SystemSetupService systemSetupService, MailUtil mailUtil) {
		this.redisSequenceFactory = redisSequenceFactory;
		this.systemSetupService = systemSetupService;
		this.mailUtil=mailUtil;
	}

	@PostConstruct
	public void init() {
		boolean b = !systemSetupService.isSetup();
		initSequence(SequenceType.One,b);
		initSequence(SequenceType.Two,b);
		initSequence(SequenceType.Three,b);
		initSequence(SequenceType.Four,b);
		initSequence(SequenceType.Five,b);
	}

	public void initSequence(SequenceType sequenceType, boolean forceInit) {
		if (forceInit || redisSequenceFactory.get(sequenceType.getKey()) <= sequenceType.getMin()
				||  redisSequenceFactory.get(sequenceType.getKey()) > sequenceType.getMax()) {
			redisSequenceFactory.init(sequenceType.getKey(), sequenceType.getMin()-1);
		}
	}
	
	/**
	 * 生成ID
	 * 
	 * @param key
	 * @return
	 */
	public long generateId(SequenceType sequenceType) {
		long id = redisSequenceFactory.generate(sequenceType.getKey());
		if (sequenceType.getMax() >= id && id >= sequenceType.getMin()) {
			String compressNumber = DisorderedCompressEncoder.compressNumber(id);
			logger.info("生成的id 十进制: " + id + " 六十四进制:" + compressNumber);
			return id;
		} else {
			String mailSubject = "《接口故障监控报警》(跨越短网址服务接口平台USM)";
			String mailBody = MessageFormat.format("生成 {0} 类型的ID {1} 失败,序列超出范围: [{2},{3}]",sequenceType.getKey(),id,sequenceType.getMin(),sequenceType.getMax());
			boolean sendMail = mailUtil.sendMail(null, mailSubject, mailBody, false, null);
			if(sendMail) {
				String[] sendTo = mailUtil.getSendTo();
				StringBuilder sb = new StringBuilder();
				if(sendTo != null) {
					for (String string : sendTo) {
						sb.append(string).append(" ");
					}
				}
				throw new UsmException(mailBody+"具体看邮件:" + sb.toString() );	
			}
			throw new UsmException(mailBody);
		}
	}

	/**
	 * 当前ID
	 * 
	 * @param key
	 * @return
	 */
	public long currentSequence(SequenceType sequenceType) {
		if (sequenceType == null) {
			return -1;
		}
		long id = redisSequenceFactory.get(sequenceType.getKey());
		if (sequenceType.getMax() >= id && id >= sequenceType.getMin()) {
			DisorderedCompressEncoder.compressNumber(id);
			return id;
		} else {
			String mailSubject = "《接口故障监控报警》(跨越短网址服务接口平台USM)";
			String mailBody = MessageFormat.format("无效的类型 ,生成 {0} 类型的ID {1} 失败,序列超出范围: [{2},{3}]",sequenceType.getKey(),id,sequenceType.getMin(),sequenceType.getMax());
			mailUtil.sendMail(null, mailSubject, mailBody, false, null);
			throw new UsmException(mailBody);
		}
	}

	public BigDecimal currentUsedRate() {
		BigDecimal used = new BigDecimal("0");
		BigDecimal total = new BigDecimal("0");
		for (SequenceType sequenceType : SequenceType.values()) {
			long id = redisSequenceFactory.get(sequenceType.getKey());
			logger.info("当前" + sequenceType.getKey() + "的序列是:" + id);
			used = used.add(new BigDecimal(id - sequenceType.min + 1));
			total = total.add(new BigDecimal(sequenceType.max-sequenceType.min+1));
		}
		logger.info("当前 使用的的序列个数是:" + used.longValue());
		if (BigDecimal.ZERO.longValue() < used.longValue() && used.longValue() < total.longValue()) {
			return used.divide(total, 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2);
		} else if (BigDecimal.ZERO.longValue() == used.longValue()) {
			return BigDecimal.ZERO.multiply(new BigDecimal(100)).setScale(2);
		} else if (total.longValue()== used.longValue()) {
			return BigDecimal.ONE.multiply(new BigDecimal(100)).setScale(2);
		} else {
			String mailSubject = "《接口故障监控报警》(跨越短网址服务接口平台USM)";
			String mailBody = "计算使用率失败";
			mailUtil.sendMail(null, mailSubject, mailBody, false, null);
			throw new UsmException("计算使用率失败!");
		}
	}
	
	/**
	 * @param key
	 * @return
	 */
	public BigDecimal currentUsedRate(SequenceType sequenceType) {
		if (sequenceType == null) {
			throw new ValidException("无效的短网址类型!");
		}
		long id = redisSequenceFactory.get(sequenceType.getKey());
		logger.info("当前" + sequenceType.getKey() + "的序列是:" + id);
		if (sequenceType.min <= id && id <= sequenceType.max) {
			BigDecimal total = new BigDecimal(sequenceType.max - sequenceType.min + 1);
			BigDecimal used = new BigDecimal(id - sequenceType.min + 1);
			return used.divide(total, 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2);
		} else if (sequenceType.min-1 == id) {
			return BigDecimal.ZERO.multiply(new BigDecimal(100)).setScale(2);
		} else if (sequenceType.max == id) {
			return BigDecimal.ONE.multiply(new BigDecimal(100)).setScale(2);
		} else {
			String mailSubject = "《接口故障监控报警》(跨越短网址服务接口平台USM)";
			String mailBody = "计算使用率失败:" + sequenceType.key;
			mailUtil.sendMail(null, mailSubject, mailBody, false, null);
			throw new UsmException("计算使用率失败!");
		}
	}

	public static enum SequenceType {

		One(SEQUENCE_ONE_LENGTH, MIN_VALUE_ONE_LENGTH, MAX_VALUE_ONE_LENGTH, 1),

		Two(SEQUENCE_TWO_LENGTH, MIN_VALUE_TWO_LENGTH, MAX_VALUE_TWO_LENGTH, 2), 
		
		Three(SEQUENCE_THREE_LENGTH, MIN_VALUE_THREE_LENGTH, MAX_VALUE_THREE_LENGTH, 3),
		
		Four(SEQUENCE_FOUR_LENGTH, MIN_VALUE_FOUR_LENGTH,	MAX_VALUE_FOUR_LENGTH,	4), 
		
		Five(SEQUENCE_FIVE_LENGTH, MIN_VALUE_FIVE_LENGTH, MAX_VALUE_FIVE_LENGTH, 5);
		
		private String key;

		private long min;

		private long max;

		private int type;

		private SequenceType(String key, long min, long max, int type) {
			this.key = key;
			this.min = min;
			this.max = max;
			this.type = type;
		}

		public String getKey() {
			return key;
		}

		public void setKey(String key) {
			this.key = key;
		}

		public long getMin() {
			return min;
		}

		public void setMin(long min) {
			this.min = min;
		}

		public long getMax() {
			return max;
		}

		public void setMax(long max) {
			this.max = max;
		}

		public static SequenceType valueOfType(int type) {
			SequenceType[] values = SequenceType.values();
			for (int i = 0; i < values.length; i++) {
				SequenceType sequenceType = values[i];
				if (sequenceType.type == type) {
					return sequenceType;
				}
			}
			return null;
		}

	}
}
